﻿// Decompiled with JetBrains decompiler
// Type: Netick.Unity.NetworkSceneManager
// Assembly: Netick.Unity, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: E128C7FD-39ED-4452-86AC-6EC748457030
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.Unity.dll
// XML documentation location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.Unity.xml

using System;
using System.Collections.Generic;
using UnityEngine.SceneManagement;

#nullable disable
namespace Netick.Unity;

[ExecutionOrder(-100000)]
public sealed class NetworkSceneManager : NetickCoreComponent
{
  internal NetworkArray<SceneInfo> NetworkedLoadedAdditiveScenes;
  internal Dictionary<int, NetworkScene> LoadedAdditiveScenes = new Dictionary<int, NetworkScene>(100);
  internal HashSet<int> PendingLoadScenes = new HashSet<int>(8);
  internal HashSet<int> PendingUnloadScenes = new HashSet<int>(8);
  private Queue<SceneLoadOp> _sceneOperations = new Queue<SceneLoadOp>(20);
  private Stack<int> _freeSceneSlots = new Stack<int>(8);
  internal List<NetworkObject> _cached = new List<NetworkObject>(512 /*0x0200*/);

  internal void Init(int maxAdditiveScenes)
  {
    this.NetworkedLoadedAdditiveScenes = new NetworkArray<SceneInfo>(maxAdditiveScenes);
    this._freeSceneSlots.Clear();
    for (int index = 0; index < this.NetworkedLoadedAdditiveScenes.Length; ++index)
      this._freeSceneSlots.Push(index);
  }

  private void OnDestroy()
  {
    if ((UnityEngine.Object) this.Sandbox == (UnityEngine.Object) null)
      return;
    foreach (KeyValuePair<int, NetworkScene> loadedAdditiveScene in this.LoadedAdditiveScenes)
    {
      if (loadedAdditiveScene.Value.Scene.IsValid())
        StaticUnitySceneManager.UnloadScene(this.Sandbox, loadedAdditiveScene.Value.Scene);
    }
    this.LoadedAdditiveScenes.Clear();
  }

  public override void NetworkStart()
  {
    if (!this.Sandbox.IsServer || !this.Sandbox.IsHost && this.Sandbox.StartMode != NetickStartMode.SinglePlayer)
      return;
    this.Sandbox.Engine.OnPostNetworkStart += new Action(this.InvokeOnPlayerConnectedForHostOneShot);
  }

  public override void NetworkDestroy()
  {
    if (!this.Sandbox.IsServer || !this.Sandbox.IsHost && this.Sandbox.StartMode != NetickStartMode.SinglePlayer)
      return;
    this.Engine.DisconnectHost();
  }

  private void InvokeOnPlayerConnectedForHostOneShot()
  {
    this.Sandbox.Engine.ConnectHost();
    this.Sandbox.Engine.OnPostNetworkStart -= new Action(this.InvokeOnPlayerConnectedForHostOneShot);
  }

  internal void LoadAdditiveScene(int buildIndex, LocalPhysicsMode localPhysicsMode)
  {
    if (this.IsClient)
      throw new NotServerException();
    ++this.Sandbox.SceneLoadIdCounter;
    int sceneLoadIdCounter = this.Sandbox.SceneLoadIdCounter;
    SceneInfo sceneInfo = new SceneInfo()
    {
      LoadId = sceneLoadIdCounter,
      SceneIndex = buildIndex,
      LocalPhysicsMode = localPhysicsMode,
      HasServerFinished = (NetworkBool) false
    };
    int num = this._freeSceneSlots.Pop();
    this._sceneOperations.Enqueue(new SceneLoadOp()
    {
      SceneInfo = sceneInfo,
      SlotIndex = num,
      Unload = (NetworkBool) false
    });
  }

  internal void UnloadAdditiveScene(NetworkScene scene)
  {
    this._sceneOperations.Enqueue(new SceneLoadOp()
    {
      NetScene = scene,
      SceneInfo = SceneInfo.GetInvalid(),
      SlotIndex = scene.SlotIndex,
      Unload = (NetworkBool) true
    });
  }

  internal void UnloadAdditiveScene(int buildIndex)
  {
    if (this.IsClient)
      throw new NotServerException();
    foreach (NetworkScene scene in this.LoadedAdditiveScenes.Values)
    {
      if (scene.Scene.buildIndex == buildIndex)
      {
        this.UnloadAdditiveScene(scene);
        break;
      }
    }
  }

  internal void UnloadAdditiveScene(Scene scene)
  {
    foreach (NetworkScene scene1 in this.LoadedAdditiveScenes.Values)
    {
      if (scene1.Scene == scene)
        this.UnloadAdditiveScene(scene1);
    }
  }

  internal void OnAdditiveSceneOperationDone(AdditiveSceneOperation op)
  {
    if (op.Load)
    {
      this.Sandbox.Scenes.Add(op.NewScene);
      this.Sandbox.NetworkSceneManager.OnAdditiveSceneLoaded(op);
    }
    else
    {
      this.OnAdditiveSceneUnloaded(op);
      this.Sandbox.Events.InvokeOnSceneOperationDone(this.Sandbox, op.NetworkSceneOperation);
    }
    StaticUnitySceneManager.ActiveOp = (SceneOperation) null;
  }

  internal void OnSceneSwitchOperationDone(SceneSwitchOperation op)
  {
    this.Sandbox.Scenes.Add(op.NewScene);
    this.Sandbox.MainScene.OnSceneLoaded(op.NewScene, op.SceneIndex, op.SceneCounter, true, false, false);
    if (op.Sandbox.IsMainSandbox)
      SceneManager.SetActiveScene(op.NewScene);
    StaticUnitySceneManager.ActiveOp = (SceneOperation) null;
  }

  private unsafe void SyncDestructionOfMainSceneObjects()
  {
    if (!this.IsClient || !this.Sandbox.HasLoadScene || this.Sandbox.MainScene.CheckedForDestroyedObjects || ((ConnectionMeta*) this.Engine.Client.ConnectedServer.RemoteUserData)->HasLoadedScene != 1)
      return;
    this._cached.Clear();
    foreach (NetworkObject networkObject in this.Sandbox.MainScene.NetworkObjects.Values)
    {
      if (networkObject.RawId == -1)
        this._cached.Add(networkObject);
    }
    foreach (NetworkObject entity in this._cached)
      this.Sandbox.ClientDestroyObject(entity);
    this.Sandbox.MainScene.CheckedForDestroyedObjects = true;
  }

  internal void Process()
  {
    if (StaticUnitySceneManager.PendingFinishedOp != null && (UnityEngine.Object) StaticUnitySceneManager.PendingFinishedOp.Sandbox == (UnityEngine.Object) this.Sandbox)
    {
      if (StaticUnitySceneManager.PendingFinishedOp is SceneSwitchOperation)
        this.OnSceneSwitchOperationDone(StaticUnitySceneManager.PendingFinishedOp as SceneSwitchOperation);
      else
        this.OnAdditiveSceneOperationDone(StaticUnitySceneManager.PendingFinishedOp as AdditiveSceneOperation);
      StaticUnitySceneManager.PendingFinishedOp = (SceneOperation) null;
    }
    else
    {
      if (!this.Sandbox.HasLoadScene || this.Sandbox.IsClient && !this.Sandbox.IsConnected)
        return;
      if (this.Sandbox.SwitchedToScene.IsValid)
      {
        if (this.Sandbox.IsServer)
          this.Sandbox.MainSceneLoadIdCounter = this.Sandbox.SceneLoadIdCounter;
        this.Sandbox.MainScene.InternalSwitchScene(this.Sandbox.SwitchedToScene.BuildIndex, this.Sandbox.SwitchedToScene.Counter);
        if (this.Sandbox.IsServer)
          this.Sandbox.MainSceneIndex = this.Sandbox.SwitchedToScene.BuildIndex;
        this.Sandbox.SwitchedToScene = SwitchedToScene.Invalid;
      }
      else
      {
        if (this.IsClient && !this.Engine.ClientSimulation.IsLastTickFull || this.PendingUnloadScenes.Count > 0 || this.PendingLoadScenes.Count > 0)
          return;
        if (this._sceneOperations.Count > 0)
        {
          SceneLoadOp sceneLoadOp = this._sceneOperations.Dequeue();
          this.NetworkedLoadedAdditiveScenes[sceneLoadOp.SlotIndex] = (bool) sceneLoadOp.Unload ? SceneInfo.GetInvalid() : sceneLoadOp.SceneInfo;
          if ((bool) sceneLoadOp.Unload)
            sceneLoadOp.NetScene.DestroySceneObjects();
        }
        this.SyncDestructionOfMainSceneObjects();
        this.ProcessSyncedLoadedAdditiveScenes();
      }
    }
  }

  private void ProcessSyncedLoadedAdditiveScenes()
  {
    for (int index = 0; index < this.NetworkedLoadedAdditiveScenes.Length; ++index)
    {
      SceneInfo loadedAdditiveScene1 = this.NetworkedLoadedAdditiveScenes[index];
      if (loadedAdditiveScene1.LoadId != -1 && !this.PendingLoadScenes.Contains(loadedAdditiveScene1.LoadId))
      {
        bool flag = true;
        foreach (KeyValuePair<int, NetworkScene> loadedAdditiveScene2 in this.LoadedAdditiveScenes)
        {
          if (loadedAdditiveScene1.LoadId == loadedAdditiveScene2.Key)
          {
            flag = false;
            if (this.Sandbox.IsClient && !loadedAdditiveScene2.Value.IsReady && (bool) loadedAdditiveScene1.HasServerFinished)
            {
              NetworkScene networkScene = loadedAdditiveScene2.Value;
              networkScene.OnSceneLoaded(networkScene.Scene, networkScene.SceneIndex, networkScene.LoadCounterId, false, false, true);
              networkScene.IsReady = true;
            }
          }
        }
        if (flag)
        {
          this.PendingLoadScenes.Add(this.NetworkedLoadedAdditiveScenes[index].LoadId);
          StaticUnitySceneManager.LoadAdditiveScene(this.Sandbox, this.NetworkedLoadedAdditiveScenes[index], index);
        }
      }
    }
    foreach (KeyValuePair<int, NetworkScene> loadedAdditiveScene in this.LoadedAdditiveScenes)
    {
      int key = loadedAdditiveScene.Key;
      if (!this.PendingUnloadScenes.Contains(key))
      {
        bool flag = true;
        for (int i = 0; i < this.NetworkedLoadedAdditiveScenes.Length; ++i)
        {
          if (this.NetworkedLoadedAdditiveScenes[i].LoadId == key)
            flag = false;
        }
        if (flag)
        {
          this.PendingUnloadScenes.Add(key);
          StaticUnitySceneManager.UnloadAdditiveScene(this.Sandbox, loadedAdditiveScene.Value, loadedAdditiveScene.Value.SlotIndex);
          loadedAdditiveScene.Value.DestroySceneObjects();
        }
      }
    }
  }

  internal void OnAdditiveSceneLoaded(AdditiveSceneOperation op)
  {
    NetworkScene networkScene = new NetworkScene(this.Sandbox, false, op.LoadCounterId, op.LocalPhysicsMode != 0, op.NewScene, op.SlotIndex);
    networkScene.NetworkSceneOperation = op.NetworkSceneOperation;
    if (this.IsServer)
    {
      SceneInfo loadedAdditiveScene = this.NetworkedLoadedAdditiveScenes[op.SlotIndex] with
      {
        HasServerFinished = (NetworkBool) true
      };
      this.NetworkedLoadedAdditiveScenes[op.SlotIndex] = loadedAdditiveScene;
      this.LoadedAdditiveScenes.Add(op.LoadCounterId, networkScene);
      this.PendingLoadScenes.Remove(op.LoadCounterId);
      networkScene.OnSceneLoaded(op.NewScene, op.SceneIndex, op.LoadCounterId, false, false, false);
    }
    else
    {
      networkScene.IsLoaded = true;
      this.LoadedAdditiveScenes.Add(op.LoadCounterId, networkScene);
      this.PendingLoadScenes.Remove(op.LoadCounterId);
    }
  }

  internal void OnAdditiveSceneUnloaded(AdditiveSceneOperation op)
  {
    this.LoadedAdditiveScenes.Remove(op.LoadCounterId);
    this.PendingUnloadScenes.Remove(op.LoadCounterId);
    if (!this.IsServer)
      return;
    this._freeSceneSlots.Push(op.SlotIndex);
  }

  public override unsafe void InternalReset()
  {
    for (int i = 0; i < this.NetworkedLoadedAdditiveScenes.Length; ++i)
      this.NetworkedLoadedAdditiveScenes[i] = SceneInfo.GetInvalid();
    this.NetworkedLoadedAdditiveScenes.InternalInit((INetickNetworkScript) this, ((INetickNetworkScript) this).State, NetickUtils.GetWordSize(sizeof (SceneInfo)), 0);
    this.NetworkedLoadedAdditiveScenes.InternalReset();
  }

  public override int InternalGetStateSizeWords()
  {
    return NetickUtils.GetWordSize(sizeof (SceneInfo)) * this.NetworkedLoadedAdditiveScenes.Length + 1;
  }
}
